#include "Listener.h"
#ifdef WS_SSL
#include "server_certificate.hpp"
#endif

namespace wsbus {
	Listener::Listener(tcp::endpoint endpoint, int threads)
		: threads_(threads)
		, ctx_(threads)
		, acceptor_(net::make_strand(ctx_))
		, isBindSuccess_(false)
	{
		beast::error_code ec;
		acceptor_.open(endpoint.protocol(), ec);
		if (ec) {
			fail(ec, "acceptor open");
			return;
		}
		//acceptor_.set_option(net::socket_base::reuse_address(true), ec);
		//if (ec) {
		//	fail(ec, "set_option");
		//	return;
		//}
		acceptor_.bind(endpoint, ec);
		if (ec) {
			fail(ec, "bind");
			return;
		}

		isBindSuccess_ = true;
		acceptor_.listen(net::socket_base::max_connections, ec);
		if (ec) {
			fail(ec, "listen");
			return;
		}

#ifdef WS_SSL
		load_server_certificate(sslctx_);
#endif
	}

	void Listener::run()
	{
		if (!isBindSuccess_) {
			return;
		}

		doAccept();
		std::vector<std::thread> t;
		for (int i = threads_ - 1; i > 0; --i) {
			t.emplace_back([this]{ ctx_.run(); });
		}
		ctx_.run();
	}

	void Listener::doAccept()
	{
		acceptor_.async_accept(net::make_strand(ctx_), beast::bind_front_handler(&Listener::onAccept, shared_from_this()));
	}

	void Listener::onAccept(beast::error_code ec, tcp::socket socket)
	{
		if (ec) {
			fail(ec, "accept");
			return;
		}
		else {
			std::cout << "[accept] address:" << socket.remote_endpoint().address().to_string() << ", port:" << socket.remote_endpoint().port() << std::endl;
#ifdef WS_SSL
			std::make_shared<Session>(std::move(socket), sslctx_, dispatcher_)->start();
#else
			std::make_shared<Session>(std::move(socket), dispatcher_)->start();
#endif
		}

		doAccept();
	}

}